package drds.plus.executor.cursor.cursor.impl.join;

import drds.plus.executor.cursor.cursor.IIndexNestLoopCursor;
import drds.plus.executor.cursor.cursor.ISortingCursor;
import drds.plus.executor.record_codec.RecordCodec;
import drds.plus.executor.record_codec.RecordCodecFactory;
import drds.plus.executor.record_codec.record.Record;
import drds.plus.executor.row_values.RowValues;
import drds.plus.executor.utils.Utils;
import drds.plus.util.GeneralUtil;
import drds.tools.Threads;

import java.util.List;


public class IndexNestLoopCursor extends JoinCursor implements IIndexNestLoopCursor {
    protected IteratorDirection iteratorDirection = null;
    //
    protected RowValues leftRowData;
    //protected Record leftJoinRecord;
    //
    protected RecordCodec rightJoinRecordCodec;
    protected Record rightJoinRecord;
    //
    protected RowValues rightCursorNextDuplicateValueRowData;
    protected ISortingCursor rightCursorCache;

    //
    protected RowValues currentJoinRowData;


    public IndexNestLoopCursor(ISortingCursor leftCursor, List leftJoinItemList, ISortingCursor rightCursor, List rightJoinItemList) throws RuntimeException {

        super(leftCursor, leftJoinItemList, rightCursor, rightJoinItemList);
        this.leftCursor = leftCursor;
        this.rightCursor = rightCursor;
        //

        this.orderByList = leftCursor.getOrderByList();
        rightJoinRecordCodec = RecordCodecFactory.newRecordCodec(Utils.convertListToColumnMetaDataList(rightJoinItemList));
        this.rightJoinRecord = rightJoinRecordCodec.newRecord();
    }


    public void beforeFirst() throws RuntimeException {
        leftCursor.beforeFirst();
    }

    public RowValues current() throws RuntimeException {
        return currentJoinRowData;
    }

    protected RowValues getLeftCursorRowData(boolean forward) throws RuntimeException {
        if (forward) {
            leftRowData = Utils.fromRowDataToArrayRowData(leftCursor.next());
        } else {
            leftRowData = Utils.fromRowDataToArrayRowData(leftCursor.prev());
        }
        return leftRowData;
    }

    public RowValues prev() throws RuntimeException {
        if (iteratorDirection == null) {
            iteratorDirection = IteratorDirection.BACKWARD;
        } else if (iteratorDirection == IteratorDirection.FORWARD) {
            throw new IllegalStateException("亲，别折腾。。先前进再后退。。暂时不支持");
        }
        /**
         * 左边的cursor next一次。然后右边的next一次拼装，如果有重复key的情况。那么标记重复key为dup,利用重复key再次构建一个cursor。
         */
        RowValues rowData = forward(false);
        currentJoinRowData = rowData;
        return rowData;
    }

    public RowValues next() throws RuntimeException {
        if (iteratorDirection == null) {
            iteratorDirection = IteratorDirection.FORWARD;
        } else if (iteratorDirection == IteratorDirection.BACKWARD) {
            throw new IllegalStateException("亲，别折腾。。先后退再前进。。暂时不支持");
        }
        /**
         * 左边的cursor next一次。然后右边的next一次拼装，如果有重复key的情况。那么标记重复key为dup,利用重复key再次构建一个cursor。
         */
        RowValues rowData = forward(true);
        currentJoinRowData = rowData;
        return rowData;
    }


    protected RowValues forward(boolean forward) throws RuntimeException {
        RowValues rowData = null;
        if (rightCursorNextDuplicateValueRowData != null) {
            rowData = processDuplicateValueRowData();
            return rowData;
        }
        while (getLeftCursorRowData(forward) != null) {
            Threads.checkInterrupted();
            setRightJoinRecord();
            boolean skipTo = rightCursor.skipTo(rightJoinRecord);
            if (skipTo) {
                rowData = join(leftRowData, rightCursor.current());
                rightCursorNextDuplicateValueRowData = rightCursor.getNextDuplicateValueRowData();
                rightCursorCache = rightCursor;
                return rowData;
            }
        }
        return null;
    }


    /**
     * 将左面的Join on columns找到。 放到右边key这个对象里。
     */
    protected void setRightJoinRecord() {
        rightJoinRecord = rightJoinRecordCodec.newRecord();
        for (int i = 0; i < leftJoinItemList.size(); i++) {
            Object value = Utils.getValue(leftRowData, leftJoinItemList.get(i));
            rightJoinRecord.put(Utils.getColumn(rightJoinItemList.get(i)).getColumnName(), value);
        }
    }

    /**
     * 处理右值重复用。 左值不变，右值因为有相同key的值，所以取右，下移指针一次。
     */
    protected RowValues processDuplicateValueRowData() throws RuntimeException {
        RowValues rowData = join(leftRowData, rightCursorNextDuplicateValueRowData);
        rightCursorNextDuplicateValueRowData = rightCursorCache.getNextDuplicateValueRowData();
        return rowData;
    }

    public String toString() {
        return toStringWithInden(0);
    }

    public String toStringWithInden(int inden) {
        String tabTittle = GeneralUtil.getTab(inden);
        String tabContent = GeneralUtil.getTab(inden + 1);
        StringBuilder sb = new StringBuilder();
        GeneralUtil.printlnToStringBuilder(sb, tabTittle + "IndexNestedLoopCursor ");
        GeneralUtil.printAFieldToStringBuilder(sb, "leftJoinColumnList", this.leftJoinItemList, tabContent);
        GeneralUtil.printAFieldToStringBuilder(sb, "rightJoinColumnList", this.rightJoinItemList, tabContent);
        GeneralUtil.printlnToStringBuilder(sb, tabContent + "leftNode:");
        sb.append(this.leftCursor.toStringWithInden(inden + 1));
        GeneralUtil.printlnToStringBuilder(sb, tabContent + "rightNode:");
        sb.append(this.rightCursor.toStringWithInden(inden + 1));
        return sb.toString();
    }

}
